<!-- index.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>学生作业管理系统</title>
    <style>
        :root { --bg:#0a0f1f; --bg2:#111533; --grid:#0b1430; --primary:#00ffc6; --secondary:#ff00a6; --accent:#8a2be2; --text:#cfe9ff; --muted:#8aa0c8; }
        body.cyberpunk { margin:0; min-height:100vh; color:var(--text); background:
            radial-gradient(1200px 600px at 10% 10%, rgba(138,43,226,0.08), transparent 60%),
            radial-gradient(800px 400px at 90% 20%, rgba(255,0,166,0.08), transparent 60%),
            linear-gradient(180deg, var(--bg), var(--bg2));
            background-image:
            repeating-linear-gradient(0deg, transparent 0 39px, rgba(11,20,48,0.4) 39px 40px),
            repeating-linear-gradient(90deg, transparent 0 39px, rgba(11,20,48,0.4) 39px 40px);
            font-family: Segoe UI, Arial, sans-serif;
            padding: 24px;
        }
        h1, h3 { color: var(--primary); text-shadow: 0 0 6px rgba(0,255,198,0.8), 0 0 18px rgba(0,255,198,0.4); letter-spacing: 0.5px; }
        a { color: var(--primary); }
        .neon-card { background: rgba(16,18,48,0.6); border: 1px solid rgba(0,255,198,0.25); box-shadow: 0 0 24px rgba(0,255,198,0.18), inset 0 0 12px rgba(255,0,166,0.12); border-radius: 10px; padding: 12px; margin: 20px 0; }
        #aiMessages { min-height: 120px; background: rgba(10,12,34,0.6); border: 1px solid rgba(138,43,226,0.35); box-shadow: inset 0 0 20px rgba(138,43,226,0.25); border-radius: 6px; padding: 10px; color: var(--text); }
        .filter-form { margin: 16px 0 20px; padding: 12px; background: rgba(16,18,48,0.45); border: 1px dashed rgba(255,0,166,0.35); border-radius: 10px; }
        label { color: var(--muted); margin-right: 6px; }
        select, input[type="text"] { background: rgba(8,10,28,0.9); color: var(--text); border: 1px solid rgba(0,255,198,0.4); outline: none; padding: 6px 8px; border-radius: 6px; box-shadow: 0 0 10px rgba(0,255,198,0.15); }
        select:focus, input[type="text"]:focus { box-shadow: 0 0 14px rgba(255,0,166,0.35), 0 0 8px rgba(0,255,198,0.35); border-color: var(--secondary); }
        table { border-collapse: collapse; width: 100%; background: rgba(10,12,34,0.55); border: 1px solid rgba(0,255,198,0.25); border-radius: 10px; overflow: hidden; }
        thead th { background: linear-gradient(90deg, rgba(0,255,198,0.18), rgba(255,0,166,0.18)); color: var(--text); text-transform: uppercase; letter-spacing: 0.4px; }
        th, td { border: 1px solid rgba(255,255,255,0.08); padding: 10px; text-align: left; }
        tbody tr:hover { background: rgba(138,43,226,0.12); }
        .no-data { text-align: center; color: #ff66cc; }
        .pagination { margin-top: 20px; }
        .pagination a, .pagination span { display: inline-block; padding: 6px 12px; margin: 0 2px; text-decoration: none; border: 1px solid rgba(0,255,198,0.35); color: var(--text); background: rgba(8,10,28,0.9); border-radius: 6px; box-shadow: 0 0 10px rgba(0,255,198,0.15); }
        .pagination a:hover { background: linear-gradient(90deg, rgba(0,255,198,0.3), rgba(255,0,166,0.3)); }
        .pagination .current { background: linear-gradient(90deg, #00ffc6, #ff00a6); color: #0a0f1f; border-color: transparent; box-shadow: 0 0 16px rgba(0,255,198,0.6), 0 0 16px rgba(255,0,166,0.6); }
        button { padding: 6px 12px; background: transparent; color: var(--primary); border: 1px solid var(--primary); border-radius: 6px; cursor: pointer; transition: all 0.2s ease; box-shadow: 0 0 10px rgba(0,255,198,0.25); }
        button:hover { color: #0a0f1f; background: linear-gradient(90deg, var(--primary), var(--secondary)); border-color: transparent; box-shadow: 0 0 16px rgba(0,255,198,0.6), 0 0 16px rgba(255,0,166,0.6); }
        input[type="text"]::placeholder { color: #7ea2c8; }
    </style>
</head>
<body class="cyberpunk">
<h1>学生作业信息展示</h1>

<div class="neon-card">
    <h3>哈吉毛</h3>
    <div id="aiMessages" style="white-space:pre-wrap;"></div>
    <input type="text" id="aiInput" placeholder="示例：查学生 张三 / 统计班级 计科一班 作业一 / 统计未提交 计科一班 作业一 / 更改 李佳诚 的 作业一 成绩为 130" style="width:70%; padding:6px;" />
    <button id="aiSend" style="padding:6px 12px;">发送</button>
    <button id="aiMic" style="padding:6px 12px;">语音输入</button>
    <button id="aiClear" style="padding:6px 12px; margin-left:8px;">清空</button>
    <div style="margin-top:8px; color:#8aa0c8;">
        快捷示例：
        <a href="#" class="aiExample" data-text="查学生 李佳诚">查学生 李佳诚</a> ·
        <a href="#" class="aiExample" data-text="统计班级 大数据23开01 作业一未提交人数">统计班级 大数据23开01 作业一未提交人数</a> ·
        <a href="#" class="aiExample" data-text="统计 大数据23开01 作业一未提交人员">统计 大数据23开01 作业一未提交人员</a> ·
        <a href="#" class="aiExample" data-text="更改 李佳诚 的 作业一 成绩为 300">更改 李佳诚 的 作业一 成绩为 300</a>
    </div>
</div>



<div class="filter-form">
    <form action="/student/index" method="get">
        <input type="hidden" name="pageNum" value="1">
        <label for="bname">班级：</label>
        <select name="bname" id="bname">
            <option value="">全部班级</option>
            <option th:each="className : ${classNames}"
                    th:value="${className}"
                    th:text="${className}"
                    th:selected="${className == selectedBname}">
            </option>
        </select>

        <label for="title">作业标题：</label>
        <select name="title" id="title">
            <option value="">全部标题</option>
            <option th:each="workTitle : ${titles}"
                    th:value="${workTitle}"
                    th:text="${workTitle}"
                    th:selected="${workTitle == selectedTitle}">
            </option>
        </select>

        <label for="name">姓名：</label>
        <input type="text" id="name" name="name" th:value="${selectedName}" placeholder="支持模糊查询">

        <button type="submit">筛选</button>
    </form>
</div>

<!-- 数据表格 -->
<table>
    <thead>
    <tr>
        <th>班级名称</th>
        <th>学生姓名</th>
        <th>作业成绩</th>
        <th>学号</th>
        <th>操作</th>
    </tr>
    </thead>
    <tbody>
    <tr th:each="student : ${students}">
        <td th:text="${student.bname}"></td>
        <td th:text="${student.name}"></td>
        <td th:text="${student.score}"></td>
        <td th:text="${student.sno}"></td>
        <td>
            <form action="/student/updateScore" method="post">
                <input type="hidden" name="name" th:value="${student.name}">
                <input type="hidden" name="title" th:value="${selectedTitle}">
                <input type="hidden" name="wid" th:value="${student.wid}">
                <input type="hidden" name="bname" th:value="${selectedBname}">
                <input type="hidden" name="pageNum" th:value="${pageInfo.pageNum}">
                <input type="hidden" name="pageSize" th:value="${pageInfo.pageSize}">
                <input type="text" name="score" placeholder="输入成绩" style="width:80px">
                <button type="submit">修改成绩</button>
            </form>
        </td>
    </tr>
    <tr th:if="${#lists.isEmpty(students)}">
        <td colspan="5" class="no-data">暂无数据</td>
    </tr>
    </tbody>
</table>

<!-- 分页控件 -->
<div class="pagination" th:if="${pageInfo.pages > 1}">
    <!-- 首页 -->
    <a th:href="@{/student/index(bname=${selectedBname}, title=${selectedTitle}, name=${selectedName}, pageNum=1)}">首页</a>

    <!-- 上一页 -->
    <a th:if="${pageInfo.hasPreviousPage}"
       th:href="@{/student/index(bname=${selectedBname}, title=${selectedTitle}, name=${selectedName}, pageNum=${pageInfo.prePage})}">上一页</a>

    <!-- 页码 -->
    <span th:each="i : ${#numbers.sequence(pageInfo.navigateFirstPage, pageInfo.navigateLastPage)}">
        <a th:if="${i != pageInfo.pageNum}"
           th:href="@{/student/index(bname=${selectedBname}, title=${selectedTitle}, name=${selectedName}, pageNum=${i})}"
           th:text="${i}"></a>
        <span th:if="${i == pageInfo.pageNum}" class="current" th:text="${i}"></span>
    </span>

    <!-- 下一页 -->
    <a th:if="${pageInfo.hasNextPage}"
       th:href="@{/student/index(bname=${selectedBname}, title=${selectedTitle}, name=${selectedName}, pageNum=${pageInfo.nextPage})}">下一页</a>

    <!-- 尾页 -->
    <a th:href="@{/student/index(bname=${selectedBname}, title=${selectedTitle}, name=${selectedName}, pageNum=${pageInfo.pages})}">尾页</a>
</div>

<!-- 分页信息 -->
<div th:text="'总人数 ' + ${totalStudents} + ' 人，当前列表 ' + ${pageInfo.total} + ' 条，' + ${pageInfo.pages} + ' 页'"></div>

<script src="/js/jquery.min.js"></script>
<script>
    (function(){
        function appendMessage(role, text){
            var container = $('#aiMessages');
            var prefix = (role === 'user' ? '我:' : '哈吉毛:');
            var txt = (text || '').toString();
            var lines = txt.split(/\r?\n/).map(function(s){ return s.trim(); }).filter(function(s){ return s.length > 0; });
            var pipeLines = lines.filter(function(s){ return s.indexOf('|') >= 0; });
            var renderTable = pipeLines.length >= 2;
            if(renderTable){
                container.append($('<div></div>').text(prefix));
                var table = $('<table></table>');
                pipeLines.forEach(function(line){
                    var tr = $('<tr></tr>');
                    line.split('|').forEach(function(cell){
                        tr.append($('<td></td>').text(cell.trim()));
                    });
                    table.append(tr);
                });
                container.append(table);
            } else {
                container.append($('<div></div>').text(prefix + ' ' + txt));
            }
            try { container.scrollTop(container[0].scrollHeight); } catch(e) {}
        }
        $('#aiSend').on('click', function(){
            var prompt = $('#aiInput').val();
            if(!prompt) return;
            appendMessage('user', prompt);
            $('#aiInput').val('');
            // 简易命令解析
            var lower = prompt.toLowerCase();
            // 成绩修改/更改命令，直接走后端解析
            if(lower.indexOf('将') === 0 || lower.indexOf('更改') === 0){
                $.ajax({
                    url:'/api/ai/chat', method:'POST', data:{prompt:prompt},
                    success:function(res){ var reply = res && res.reply ? res.reply : '无响应'; appendMessage('ai', reply); try{ alert('成绩更改成功'); location.reload(); }catch(e){} },
                    error:function(){ appendMessage('ai','请求失败'); }
                });
                return;
            }
            if(lower.indexOf('查学生') === 0){
                var name = prompt.replace('查学生','').replace('的成绩','').trim();
                $.post('/api/ai/student-submissions',{name:name}, function(res){
                    var list = res && res.list ? res.list : [];
                    if(list.length===0){ appendMessage('ai','未查询到该学生提交记录'); return; }
                    var lines = list.map(function(x){ var t = x.title && x.title.length>0 ? x.title : (x.wid ? ('第'+x.wid+'次作业') : '无标题'); return t+' | 分数:'+ (x.score||'空') +' | 班级:'+ (x.bname||'') +' | 姓名:'+ (x.name||'')+' | 学号:'+ (x.sno||'');});
                    appendMessage('ai', lines.join('\n'));
                }).fail(function(){ appendMessage('ai','请求失败');});
                return;
            }
            if(lower.indexOf('查询学生') === 0){
                var name2 = prompt.replace('查询学生','').replace('的成绩','').trim();
                $.post('/api/ai/student-submissions',{name:name2}, function(res){
                    var list = res && res.list ? res.list : [];
                    if(list.length===0){ appendMessage('ai','未查询到该学生提交记录'); return; }
                    var lines = list.map(function(x){ var t = x.title && x.title.length>0 ? x.title : (x.wid ? ('第'+x.wid+'次作业') : '无标题'); return t+' | 分数:'+ (x.score||'空') +' | 班级:'+ (x.bname||'') +' | 姓名:'+ (x.name||'')+' | 学号:'+ (x.sno||'');});
                    appendMessage('ai', lines.join('\n'));
                }).fail(function(){ appendMessage('ai','请求失败');});
                return;
            }
            if(lower.indexOf('查询') === 0 && prompt.endsWith('的成绩')){
                var name3 = prompt.substring(2, prompt.length-3).replace(/^学生/, '').trim();
                $.post('/api/ai/student-submissions',{name:name3}, function(res){
                    var list = res && res.list ? res.list : [];
                    if(list.length===0){ appendMessage('ai','未查询到该学生提交记录'); return; }
                    var lines = list.map(function(x){ var t = x.title && x.title.length>0 ? x.title : (x.wid ? ('第'+x.wid+'次作业') : '无标题'); return t+' | 分数:'+ (x.score||'空') +' | 班级:'+ (x.bname||'') +' | 姓名:'+ (x.name||'')+' | 学号:'+ (x.sno||'');});
                    appendMessage('ai', lines.join('\n'));
                }).fail(function(){ appendMessage('ai','请求失败');});
                return;
            }
            if(lower.indexOf('统计班级') === 0){
                var rest = prompt.replace('统计班级','').trim();
                var idxNum = rest.indexOf('未提交人数');
                var idxList = rest.indexOf('未提交人员');
                if(idxNum >= 0 || idxList >= 0){
                    var endIdx = idxNum >= 0 ? idxNum : idxList;
                    var scope = rest.substring(0, endIdx).trim();
                    var ti = scope.indexOf('作业');
                    var bname = ''; var title = '';
                    if(ti > 0){ bname = scope.substring(0, ti).replace('班学生','').replace('班级','').replace('班','').trim(); title = scope.substring(ti).trim(); }
                    else { var tX = scope.replace('班学生',' ').replace('班级',' ').replace('班',' ').trim(); var psX = tX.split(/\s+/); if(psX.length>=2){ bname = psX[0]; title = psX[1]; } }
                    $.post('/api/ai/unsubmitted',{bname:bname, title:title}, function(res){
                        var list = res && res.list ? res.list : [];
                        if(idxNum >= 0){
                            var n = list.length;
                            var line = '班级:'+ bname +' | 标题:'+ title +' | 未提交人数:'+ n;
                            appendMessage('ai', line);
                        } else {
                            if(list.length===0){ appendMessage('ai','班级:'+ bname +' | 标题:'+ title +' | 未提交人员: 无'); return; }
                            var header = '班级:'+ bname +' | 标题:'+ title +' | 未提交人员:';
                            var lines = list.map(function(x){return (x.bname||'')+' | '+(x.name||'')+' | 学号:'+ (x.sno||'');});
                            appendMessage('ai', [header].concat(lines).join('\n'));
                        }
                    }).fail(function(){ appendMessage('ai','请求失败');});
                    return;
                }
                var parts = rest.split(/\s+/);
                var bname2 = parts[0]||''; var title2 = parts[1]||'';
                $.post('/api/ai/class-stats',{bname:bname2, title:title2}, function(res){
                    var list = res && res.list ? res.list : [];
                    if(list.length===0){ appendMessage('ai','无统计数据'); return; }
                    var lines = list.map(function(x){ var total=x.totalCount||0; var submitted=x.submittedCount||0; var unsubmitted= total - submitted; return (x.bname||'未知班级')+ ' | 总人数:'+total+' | 已提交:'+submitted+' | 未提交:'+unsubmitted;});
                    appendMessage('ai', lines.join('\n'));
                }).fail(function(){ appendMessage('ai','请求失败');});
                return;
            }
            if(lower.indexOf('统计未提交') === 0){
                var rest2 = prompt.replace('统计未提交','').trim();
                var parts2 = rest2.split(/\s+/);
                var bname2 = parts2[0]||''; var title2 = parts2[1]||'';
                $.post('/api/ai/unsubmitted',{bname:bname2, title:title2}, function(res){
                    var list = res && res.list ? res.list : [];
                    if(list.length===0){ appendMessage('ai','该范围内暂无未提交学生'); return; }
                    var lines = list.map(function(x){return (x.bname||'')+' | '+(x.name||'')+' | 学号:'+ (x.sno||'');});
                    appendMessage('ai', lines.join('\n'));
                }).fail(function(){ appendMessage('ai','请求失败');});
                return;
            }
            if(lower.indexOf('统计') === 0 && prompt.indexOf('未提交人数') > 0){
                var body = prompt.substring(2).trim();
                var idxNt = body.indexOf('未提交人数');
                var scope = idxNt>0 ? body.substring(0, idxNt).trim() : body;
                var ti = scope.indexOf('作业');
                var bnameX = '', titleX = '';
                if(ti>0){ bnameX = scope.substring(0,ti).replace('班学生','').replace('班级','').replace('班','').trim(); titleX = scope.substring(ti).trim(); }
                else { var tX = scope.replace('班学生',' ').replace('班级',' ').replace('班',' ').trim(); var psX = tX.split(/\s+/); if(psX.length>=2){ bnameX = psX[0]; titleX = psX[1]; } }
                $.post('/api/ai/unsubmitted',{bname:bnameX, title:titleX}, function(res){
                    var list = res && res.list ? res.list : [];
                    var n = list.length;
                    var line = '班级:'+ bnameX +' | 标题:'+ titleX +' | 未提交人数:'+ n;
                    appendMessage('ai', line);
                }).fail(function(){ appendMessage('ai','请求失败');});
                return;
            }
            if(lower.indexOf('统计') === 0 && prompt.indexOf('未提交人员') > 0){
                var body2 = prompt.substring(2).trim();
                var idxNt2 = body2.indexOf('未提交人员');
                var scope2 = idxNt2>0 ? body2.substring(0, idxNt2).trim() : body2;
                var ti2 = scope2.indexOf('作业');
                var bnameY = '', titleY = '';
                if(ti2>0){ bnameY = scope2.substring(0,ti2).replace('班学生','').replace('班级','').replace('班','').trim(); titleY = scope2.substring(ti2).trim(); }
                else { var tY = scope2.replace('班学生',' ').replace('班级',' ').replace('班',' ').trim(); var psY = tY.split(/\s+/); if(psY.length>=2){ bnameY = psY[0]; titleY = psY[1]; } }
                $.post('/api/ai/unsubmitted',{bname:bnameY, title:titleY}, function(res){
                    var list = res && res.list ? res.list : [];
                    if(list.length===0){ appendMessage('ai','班级:'+ bnameY +' | 标题:'+ titleY +' | 未提交人员: 无'); return; }
                    var header = '班级:'+ bnameY +' | 标题:'+ titleY +' | 未提交人员:';
                    var lines = list.map(function(x){return (x.bname||'')+' | '+(x.name||'')+' | 学号:'+ (x.sno||'');});
                    appendMessage('ai', [header].concat(lines).join('\n'));
                }).fail(function(){ appendMessage('ai','请求失败');});
                return;
            }
            if(lower.indexOf('统计提交') === 0){
                var rest3 = prompt.replace('统计提交','').trim();
                var parts3 = rest3.split(/\s+/);
                var bname3 = parts3[0]||''; var title3 = parts3[1]||'';
                $.post('/api/ai/class-submissions',{bname:bname3, title:title3}, function(res){
                    var list = res && res.list ? res.list : [];
                    if(list.length===0){ appendMessage('ai','无数据'); return; }
                    var lines = list.map(function(x){ return (x.bname||'')+' | '+(x.name||'')+' | 学号:'+(x.sno||'')+' | '+(x.title||'')+' | 分数:'+ (x.score||'空') +' | '+(x.submitted?'已提交':'未提交'); });
                    appendMessage('ai', lines.join('\n'));
                }).fail(function(){ appendMessage('ai','请求失败');});
                return;
            }
            if(lower.indexOf('统计') === 0 && prompt.endsWith('的提交情况')){
                var body = prompt.substring(2, prompt.length-5).trim();
                var bnameX=''; var titleX='';
                var idxX = body.indexOf('作业');
                if(idxX > 0){
                    bnameX = body.substring(0, idxX).replace('班学生','').replace('班','').trim();
                    titleX = body.substring(idxX).trim();
                } else {
                    var tX = body.replace('班学生',' ').replace('班',' ').trim();
                    var psX = tX.split(/\s+/);
                    if(psX.length>=2){ bnameX = psX[0]; titleX = psX[1]; }
                }
                if(!bnameX || !titleX){ appendMessage('ai','请按格式：统计班级 班级名 作业标题 的提交情况'); return; }
                $.post('/api/ai/class-submissions',{bname:bnameX, title:titleX}, function(res){
                    var list = res && res.list ? res.list : [];
                    if(list.length===0){ appendMessage('ai','无数据'); return; }
                    var lines = list.map(function(x){ return (x.bname||'')+' | '+(x.name||'')+' | 学号:'+(x.sno||'')+' | '+(x.title||'')+' | 分数:'+ (x.score||'空') +' | '+(x.submitted?'已提交':'未提交'); });
                    appendMessage('ai', lines.join('\n'));
                }).fail(function(){ appendMessage('ai','请求失败');});
                return;
            }
            // 默认走千问模型对话
            $.ajax({
                url: '/api/ai/chat',
                method: 'POST',
                data: { prompt: prompt },
                success: function(res){
                    var reply = res && res.reply ? res.reply : '无响应';
                    appendMessage('ai', reply);
                },
                error: function(){
                    appendMessage('ai', '请求失败');
                }
            });
        });
        $('#aiInput').on('keydown', function(e){
            if (e.key === 'Enter') {
                e.preventDefault();
                $('#aiSend').click();
            }
        });
        $('#aiClear').on('click', function(){ $('#aiMessages').empty(); });
        $(document).on('click', 'a.aiExample', function(e){ e.preventDefault(); var t=$(this).data('text'); $('#aiInput').val(t); $('#aiSend').click(); });
        $(document).on('submit', 'form[action="/student/updateScore"]', function(e){ e.preventDefault(); var f=$(this); $.ajax({ url:'/student/updateScore', method:'POST', data:f.serialize(), success:function(){ try{ alert('成绩更改成功'); location.reload(); }catch(e){} }, error:function(){ try{ alert('更新失败'); }catch(e){} } }); });
        var SR = window.SpeechRecognition || window.webkitSpeechRecognition;
        if (SR) {
            var rec = new SR();
            rec.lang = 'zh-CN';
            rec.interimResults = true;
            rec.maxAlternatives = 1;
            rec.continuous = false;
            $('#aiMic').on('click', function(){
                $(this).prop('disabled', true).text('识别中...');
                try { rec.start(); } catch(e) {}
            });
            rec.onresult = function(e){
                var buf = '';
                for (var i = e.resultIndex; i < e.results.length; i++) {
                    buf += e.results[i][0].transcript;
                }
                $('#aiInput').val(buf);
            };
            rec.onend = function(){
                $('#aiMic').prop('disabled', false).text('语音输入');
            };
            rec.onerror = function(){
                $('#aiMic').prop('disabled', false).text('语音输入');
                appendMessage('ai', '语音识别失败');
            };
        } else {
            $('#aiMic').prop('disabled', true).text('不支持语音');
        }
    })();
</script>

</body>
</html>
